home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / OpenGL / backtrace / scene.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  25.5 KB  |  1,056 lines

  1. /*
  2.  * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
  3.  * ALL RIGHTS RESERVED 
  4.  * Permission to use, copy, modify, and distribute this software for 
  5.  * any purpose and without fee is hereby granted, provided that the above
  6.  * copyright notice appear in all copies and that both the copyright notice
  7.  * and this permission notice appear in supporting documentation, and that 
  8.  * the name of Silicon Graphics, Inc. not be used in advertising
  9.  * or publicity pertaining to distribution of the software without specific,
  10.  * written prior permission. 
  11.  *
  12.  * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
  13.  * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
  14.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
  15.  * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
  16.  * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
  17.  * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
  18.  * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
  19.  * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
  20.  * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
  21.  * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
  22.  * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
  23.  * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
  24.  * 
  25.  * US Government Users Restricted Rights 
  26.  * Use, duplication, or disclosure by the Government is subject to
  27.  * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
  28.  * (c)(1)(ii) of the Rights in Technical Data and Computer Software
  29.  * clause at DFARS 252.227-7013 and/or in similar or successor
  30.  * clauses in the FAR or the DOD or NASA FAR Supplement.
  31.  * Unpublished-- rights reserved under the copyright laws of the
  32.  * United States.  Contractor/manufacturer is Silicon Graphics,
  33.  * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
  34.  *
  35.  * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
  36.  */
  37. #include <GL/glu.h>
  38. #include <GL/glx.h>
  39.  
  40. #include <math.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43.  
  44. /* XXX */
  45. #include <malloc.h>
  46.  
  47. extern "C" {
  48. #include <tk.h>
  49. };
  50.  
  51. #include "Unitdisk.h"
  52.  
  53. #include "scene.h"
  54.  
  55. const GLfloat I[16] = {
  56.   1, 0, 0, 0,
  57.   0, 1, 0, 0,
  58.   0, 0, 1, 0,
  59.   0, 0, 0, 1};
  60.  
  61. Color white;
  62. Color black;
  63.  
  64. const double M_2PI = 2.0 * M_PI;
  65. const float scene_fudge = .000001;
  66.  
  67. /* Lights are native to the xz plane and are rotated into position - 
  68.  * shadows and refraction will not have to be changed if lights are 
  69.  * just rotating about the z axis */
  70. light lights[] = {
  71.   {{1, 0, 0, 1}, {0, 0, 0, 0}, {1, 0, 0, 0}, 
  72.      {1, 0, 0, 0,  0, 1, 0, 0,   0, 0, 1, 0,   0, 0, 0, 1},
  73.     "Red", 1},
  74.   {{0, 1, 0, 1}, {0, 0, 0, 0}, {0, 1, 0, 0},
  75.      {1, 0, 0, 0,  0, 1, 0, 0,   0, 0, 1, 0,   0, 0, 0, 1},
  76.     "Green", 1},
  77.   {{0, 0, 1, 1}, {0, 0, 0, 0}, {0, 0, 1, 0},
  78.      {1, 0, 0, 0,  0, 1, 0, 0,   0, 0, 1, 0,   0, 0, 0, 1},
  79.     "Blue", 1}
  80. };
  81. GLfloat light_init_position[nlights][4] = 
  82. {{1.5, 0, 2.5, 1}, {1, 0, 3, 1}, {2, 0, 3, 1}};
  83. GLfloat light_init_rotation[nlights] = {135, 0, 90};
  84. GLfloat light_rotation[nlights];
  85.  
  86. Color world_ambient(.25, .25, .25);
  87.  
  88. GLfloat index = indices[def_refraction_index].index;
  89.  
  90. GLfloat square_ambient[4] = {.25, .25, .25, 1};
  91. GLfloat square_diffuse[4] = {1, 1, 1, 1};
  92. GLfloat square_specular[4] = {0, 0, 0, 1};
  93.  
  94. const GLfloat fov = 45.0;
  95. GLfloat aspect = 1.0;
  96. GLfloat eyep[3] = {-6, 0, 6};
  97. GLfloat lookp[3] = {0, 0, 1};
  98.  
  99.  
  100.  
  101. static GLXContext glx_context;
  102.  
  103. const int max_args = 20;
  104.  
  105. static int list_square;
  106. static int lists_shadows;
  107. static int lists_refraction;
  108. static int lists_lights = 5;
  109. static int list_sphere = 4;
  110. static int list_spheredisk = 9;
  111. static int list_lights_on = 6;
  112. static int list_lights_off = 7;
  113. static int list_light_draw = 8;
  114.  
  115. int draw_square = 1;
  116. int draw_shadows = 1;
  117. int draw_refraction = 1;
  118. int draw_sphere = 1;
  119. int draw_lights = 1;
  120. int draw_texture = 0;
  121.  
  122. int possible_divisions[] = {10, 20, 30, 40};
  123.  
  124. // Sphere is stored as floats - more efficient
  125. GLfloat *spherepts = NULL;
  126. int nspherepts = 0;
  127. int spherediv = 0;
  128. Point sphere_position = {0, 0, 1, 1};
  129. GLfloat sphere_size = .5;
  130. const GLfloat sphere_ambient[4] = {0, 0, 0, 0};
  131. const GLfloat sphere_specular[4] = {0, 0, 0, 0};
  132. Unitdisk sphere_disk;
  133. static void sphere_build();
  134. static void sphere_list_init();
  135. static void sphere_draw();
  136.  
  137. static void square_list_init();
  138.  
  139. static void lights_init_onoff();
  140. static void lights_init_position();
  141. static void lights_init_position(int i);
  142. static void lights_list_init();
  143. static void lights_list_init(int n);
  144.  
  145. static void light_draw_list_init();
  146.  
  147. Unitdisk disks[nlights];
  148. int diskdiv = possible_divisions[def_divisions_index];
  149. static void disk_build();
  150. static void disk_build(int disk);
  151.  
  152.  
  153. Unitdisk shadows[nlights];
  154. static void shadow_list_init();
  155. static void shadow_list_init(int n);
  156. static void shadow_draw(int n);
  157.  
  158. Unitdisk refraction[nlights];
  159. static void refraction_list_init();
  160. static void refraction_list_init(int n);
  161.  
  162. static void shadow_refraction_full_build();
  163. static void shadow_refraction_full_build(int n);
  164.  
  165. void scene_init();
  166. static void lists_init();
  167. static void lights_init();
  168. static int lights_move(int light, float dr, float dphi, float dtheta, 
  169.                int update);
  170. static void lights_move_update(int light, int dr, int dphi, int dtheta);
  171.  
  172. void scene_draw();
  173.  
  174. void texture_init();
  175. TK_RGBImageRec *teximage = NULL;
  176.  
  177. inline float sign(float a) 
  178. {
  179.   // This is badly written so let's not call it too often, 'k?
  180.   return (a > 0) ? 1 : (a < 0) ? -1 : 0;
  181. }
  182.  
  183. inline double degrees(double a)
  184. {
  185.   return (a * 180.0 / M_PI);
  186. }
  187.  
  188. inline double radians(double a)
  189. {
  190.   return (a * M_PI / 180.0);
  191. }
  192.  
  193. inline double degrees_clamp(double a)
  194. {
  195.   while (a < 0.0) a += 360.0;
  196.   while (a > 360.0) a -= 360.0;
  197.   return a;
  198. }
  199.  
  200. inline double radians_clamp(double a)
  201. {
  202.   while (a < 0.0) a += M_2PI;
  203.   while (a > M_2_PI) a -= M_2PI;
  204.   return a;
  205. }
  206.  
  207. void scene_init()
  208. {
  209.   int i;
  210.  
  211.   white.c[0] = white.c[1] = white.c[2] = white.c[3] = 1;
  212.   black.c[0] = black.c[1] = black.c[2] = 0;
  213.   black.c[3] = 1;
  214.  
  215.   lists_init();
  216.  
  217.  
  218.   for (i = 0; i < nlights; i++) {
  219.     lights[i].pos = light_init_position[i];
  220.     light_rotation[i] = light_init_rotation[i];
  221.     lights_init_position(i);
  222.   }
  223.  
  224.   divisions_change(possible_divisions[def_divisions_index]);
  225.  
  226.   lights_init_onoff();
  227.   lights_init();
  228.   lights_init_position();
  229.  
  230.   texture_init();
  231.  
  232.   glClearStencil(0);
  233.  
  234.   // This is for profiling
  235.   // exit(0);
  236. }
  237.  
  238. static void scene_project()
  239. {
  240.   glMatrixMode(GL_PROJECTION);
  241.   gluPerspective(fov, aspect, 0.01, 20.0);
  242.   gluLookAt(eyep[0], eyep[1], eyep[2], lookp[0], lookp[1], lookp[2],
  243.             1, 0, 0);
  244. }
  245.  
  246. static void scene_rasterize()
  247. {
  248.   int i;
  249.  
  250.   glLoadName(name_square);
  251.   if (draw_square) {
  252.     if (draw_texture) glEnable(GL_TEXTURE_2D);
  253.     glCallList(list_square);
  254.     glDisable(GL_TEXTURE_2D);
  255.   }
  256.   if (draw_shadows) 
  257.     for (i = 0; i < nlights; i++) 
  258.       if (lights[i].on) {
  259.     glPushMatrix();
  260.     glRotatef(-light_rotation[i], 0, 0, 1);
  261.     glCallList(lists_shadows + i);
  262.     glPopMatrix();
  263.       }
  264.   if (draw_refraction) 
  265.     for (i = 0; i < nlights; i++) 
  266.       if (lights[i].on) {
  267.     glPushMatrix();
  268.     glRotatef(-light_rotation[i], 0, 0, 1);
  269.     glCallList(lists_refraction + i);
  270.     glPopMatrix();
  271.       }
  272.  
  273.   glLoadName(name_sphere);
  274.   /* Drawing the sphere here makes the sphere visible through itself when we
  275.    * do the refraction redraw hack -- for now, just don't draw it */
  276.   //  if (draw_sphere) glCallList(list_sphere);
  277.  
  278.   for (i = 0; i < nlights; i++) 
  279.     if (draw_lights) glCallList(lists_lights + i);
  280. }
  281.  
  282. /* This draws an image of the scene seen through the sphere */
  283. static void scene_draw_refracted()
  284. {
  285.   int i;
  286.  
  287.   if (!draw_sphere) return;
  288.  
  289.  
  290.   /* Draw an image of the sphere into the stencil plane  - 
  291.    * must do this every time in case the lights have moved in front
  292.    * of it */
  293.   glEnable(GL_STENCIL_TEST);
  294.   glClearStencil(0);
  295.   glClear(GL_STENCIL_BUFFER_BIT);
  296.   glStencilFunc(GL_ALWAYS, 0x1, 0x1);
  297.   glStencilOp(GL_REPLACE, GL_KEEP, GL_REPLACE);
  298.   
  299.   glColorMask(0, 0, 0, 0);
  300.  
  301.   glMatrixMode(GL_PROJECTION);
  302.   glLoadIdentity();
  303.   scene_project();
  304.  
  305.   glEnable(GL_DEPTH_TEST);
  306.   glEnable(GL_CULL_FACE);
  307.   glCallList(list_sphere);
  308.   glDisable(GL_CULL_FACE);
  309.   glDisable(GL_DEPTH_TEST);
  310.  
  311.   glColorMask(1, 1, 1, 1);
  312.  
  313.  
  314.   /* Set up a transform with a wider field of view  - this is inaccurate 
  315.    * but I don't have time to do it right */
  316.   glMatrixMode(GL_PROJECTION);
  317.   glLoadIdentity();
  318.   gluPerspective(fov * index, aspect, 0.01, 20.0);
  319.   gluLookAt(eyep[0], eyep[1], eyep[2], lookp[0], lookp[1], lookp[2],
  320.             1, 0, 0);
  321.   glMatrixMode(GL_MODELVIEW);
  322.   glLoadIdentity();
  323.  
  324.  
  325.   /* Set up the stencil stuff which will be used to draw the image */
  326.   glStencilFunc(GL_NOTEQUAL, 0x0, 0xffffffff);
  327.   glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  328.  
  329.  
  330.   /* Draw the image, gambling that we'll never see anything but the
  331.    * floor through the table */
  332.   glLoadName(name_sphere);
  333.   if (draw_texture) glEnable(GL_TEXTURE_2D);
  334.   if (draw_square) glCallList(list_square);
  335.   if (draw_shadows)     
  336.     for (i = 0; i < nlights; i++) 
  337.       if (lights[i].on) {
  338.     glPushMatrix();
  339.     glRotatef(-light_rotation[i], 0, 0, 1);
  340.     glCallList(lists_shadows + i);
  341.     glPopMatrix();
  342.       }
  343.   if (draw_refraction) 
  344.     for (i = 0; i < nlights; i++) 
  345.       if (lights[i].on) {
  346.     glPushMatrix();
  347.     glRotatef(-light_rotation[i], 0, 0, 1);
  348.     glCallList(lists_refraction + i);
  349.     glPopMatrix();
  350.       }
  351.   glDisable(GL_TEXTURE_2D);
  352.  
  353.  
  354.   /* Draw the sphere to make it look like it
  355.    * has some substance */
  356.   glMatrixMode(GL_PROJECTION);
  357.   glLoadIdentity();
  358.   scene_project();
  359.   glCallList(list_spheredisk);
  360.  
  361.   glDisable(GL_STENCIL_TEST);
  362. }
  363.  
  364.  
  365. void scene_draw() 
  366. {
  367.   glMatrixMode(GL_PROJECTION);
  368.   glLoadIdentity();
  369.  
  370.   glMatrixMode(GL_MODELVIEW);
  371.   glLoadIdentity();
  372.  
  373.   scene_project();
  374.  
  375.   /* Should draw an image of the square into the stencil buffer 
  376.    * to make sure that refractions which are not on the square do not get
  377.    * drawn, but it can wait. */
  378.  
  379.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  380.   scene_rasterize();
  381.  
  382.   scene_draw_refracted();
  383.  
  384. }
  385.  
  386. const int pick_maxz = 0xffffffff;
  387.  
  388. int scene_pick(GLdouble x, GLdouble y)
  389. {
  390.   GLuint buffer[128];
  391.   GLint vp[4], nhits, nnames;
  392.   GLuint minz, hit = name_background;
  393.   GLint i, j;
  394.   
  395.   glMatrixMode(GL_MODELVIEW);
  396.   glLoadIdentity();
  397.   
  398.   glMatrixMode(GL_PROJECTION);
  399.   glLoadIdentity();
  400.   
  401.   glGetIntegerv(GL_VIEWPORT, vp);
  402.   
  403.   glSelectBuffer(128, buffer);
  404.   glRenderMode(GL_SELECT);
  405.  
  406.   // Where is this supposed to go, anyway?
  407.   gluPickMatrix(x, vp[3] - y, 1, 1, vp);
  408.   
  409.   scene_project();
  410.  
  411.   glMatrixMode(GL_MODELVIEW);
  412.  
  413.   glInitNames();
  414.   glPushName(name_background);
  415.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  416.   scene_rasterize();
  417.   glFlush();
  418.   nhits = glRenderMode(GL_RENDER);
  419.  
  420.   minz = pick_maxz;
  421.   for (i = j = 0; j < nhits; j++) {
  422.     nnames = buffer[i];
  423.     i++;
  424.     if (buffer[i] < minz) {
  425.       minz = buffer[i];
  426.       hit = buffer[i + 1 + nnames];
  427.     } 
  428.     i++;
  429.     i += nnames + 1;
  430.   }
  431.   if (minz == pick_maxz) return name_background;
  432.   else return hit;
  433. }
  434.  
  435. void scene_reset_lights() 
  436. {
  437.   int i;
  438.   for (i = 0; i < nlights; i++) {
  439.     lights[i].pos = light_init_position[i];
  440.     light_rotation[i] = light_init_rotation[i];
  441.   }
  442.   lights_init_position();
  443.   lights_list_init();
  444. }
  445.  
  446. static void square_list_init()
  447. {
  448.   GLfloat x, y, inc;
  449.   int i, j;  
  450.   glNewList(list_square, GL_COMPILE);
  451.   glLoadName(name_square);
  452.   glNormal3f(0, 0, 1);
  453.   glEnable(GL_LIGHTING);
  454.   glCallList(list_lights_on);
  455.   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, square_ambient);
  456.   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, square_diffuse);
  457.   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, square_specular);
  458.   inc = 10.0 / diskdiv;
  459.   glEnable(GL_CULL_FACE);
  460.  
  461.   for (i = 0, y = -5.0; i < diskdiv; i++, y += inc) {
  462.     glBegin(GL_TRIANGLE_STRIP);
  463.     for (j = 0, x = -5.0; j <= diskdiv; j++, x += inc) {
  464.       glTexCoord2f(x, y + inc);
  465.       glVertex2f(x, y + inc);
  466.       glTexCoord2f(x, y);
  467.       glVertex2f(x, y);
  468.     }
  469.     glEnd();
  470.   }
  471.  
  472.   glDisable(GL_CULL_FACE);
  473.   glCallList(list_lights_off);
  474.   glDisable(GL_LIGHTING);
  475.   glEndList();
  476. }
  477.  
  478. static void spheredisk_list_init()
  479. {
  480.   glNewList(list_spheredisk, GL_COMPILE);
  481.   glEnable(GL_BLEND);
  482.   glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
  483.   glEnable(GL_LIGHTING);
  484.   glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
  485.   glEnable(GL_COLOR_MATERIAL);
  486.   glMaterialfv(GL_AMBIENT, GL_FRONT_AND_BACK, sphere_ambient);
  487.   glMaterialfv(GL_SPECULAR, GL_FRONT_AND_BACK, sphere_specular);
  488.   glCallList(list_lights_on);
  489.   sphere_disk.draw();
  490.   glCallList(list_lights_off);
  491.   glDisable(GL_COLOR_MATERIAL);
  492.   glDisable(GL_LIGHTING);
  493.   glDisable(GL_BLEND);
  494.   glEndList();
  495. }
  496.  
  497. void lights_onoff(int light, int val)
  498. {
  499.   lights[light].on = val;
  500.   lights_init_onoff();
  501.   lights_list_init(light);
  502.   square_list_init();
  503. }
  504.  
  505. void refraction_change(GLfloat refraction)
  506. {
  507.   if (refraction == index) return;
  508.   index = refraction;
  509.   shadow_refraction_full_build();
  510.   refraction_list_init();
  511. }
  512.  
  513. void divisions_change(int divisions)
  514. {
  515.   Point eye, look;
  516.  
  517.   if (divisions != spherediv) {
  518.     spherediv = divisions;
  519.  
  520.     light_draw_list_init();
  521.     lights_list_init();
  522.  
  523.     sphere_disk.set_divisions(spherediv, spherediv);
  524.     sphere_disk.fill_points();
  525.     sphere_disk.set_colors(white);
  526.     sphere_disk.scale_alpha_by_z();
  527.     eye = eyep;
  528.     look = lookp;
  529.     sphere_disk.face_direction((eye - look).unit());
  530.     sphere_disk.copy_normals_from_points();
  531.     sphere_disk.scale_translate(sphere_size, sphere_position);
  532.     sphere_build();
  533.     sphere_list_init();
  534.  
  535.     diskdiv = divisions;
  536.     disk_build();
  537.     shadow_refraction_full_build();
  538.     square_list_init();
  539.     spheredisk_list_init();
  540.     shadow_list_init();
  541.     refraction_list_init();
  542.   }
  543. }
  544.  
  545. int scene_move(int name, float dr, float dphi, float dtheta, int update)
  546. {
  547.   switch(name) {
  548.   case name_background:
  549.     return 0;
  550.   case name_square:
  551.     return 0;
  552.   case name_sphere:
  553.     return 0;
  554.   default:
  555.     if (name < name_lights || name > name_lights + nlights) return 0;
  556.     return lights_move(name - name_lights, dr, dphi, dtheta, update);
  557.   }
  558. }
  559.  
  560. void scene_move_update(int name, int dr, int dphi, int dtheta)
  561. {
  562.   switch(name) {
  563.   case name_background:
  564.     break;
  565.   case name_square:
  566.     break;
  567.   case name_sphere:
  568.     break;
  569.   default:
  570.     if (name < name_lights || name > name_lights + nlights) break;
  571.     lights_move_update(name - name_lights, dr, dphi, dtheta);
  572.     break;
  573.   }
  574. }
  575.  
  576.  
  577. static void lights_init_onoff()
  578. {
  579.   int i;
  580.   
  581.   glNewList(list_lights_on, GL_COMPILE);
  582.   for (i = 0; i < nlights; i++) 
  583.     if (lights[i].on) glEnable(GL_LIGHT0 + i);
  584.     else glDisable(GL_LIGHT0 + i);
  585.   glEndList();
  586.   
  587.   glNewList(list_lights_off, GL_COMPILE);
  588.   for (i = 0; i < nlights; i++) glDisable(GL_LIGHT0 + i);
  589.   glEndList();
  590. }
  591.  
  592.  
  593.  
  594. static void lights_init_position()
  595. {
  596.   int i;
  597.  
  598.   for (i = 0; i < nlights; i++) lights_init_position(i);
  599.  
  600. }
  601.  
  602. static void lights_init_position(int i) 
  603. {
  604.   Point l, d;
  605.  
  606.   glMatrixMode(GL_MODELVIEW);
  607.   glLoadIdentity();
  608.   glMatrixMode(GL_PROJECTION);
  609.   glLoadIdentity();
  610.   
  611.   l = lights[i].pos;
  612.   l.pt[0] = lights[i].pos.pt[0] * cos(radians(light_rotation[i]));
  613.   l.pt[1] = lights[i].pos.pt[0] * -sin(radians(light_rotation[i]));
  614.   d = (sphere_position - l).unit();
  615.   glLightfv(GL_LIGHT0 + i, GL_POSITION, l.pt);
  616.   glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, d.pt);
  617. }
  618.  
  619. static void lights_list_init()
  620. {
  621.   int i;
  622.   for (i = 0; i < nlights; i++) lights_list_init(i);
  623. }
  624.  
  625. static void lights_list_init(int n)
  626. {
  627.   Color c;
  628.  
  629.   glNewList(lists_lights + n, GL_COMPILE);
  630.   if (lights[n].on) {
  631.     glLoadName(name_lights + n);
  632.     
  633.     glEnable(GL_DEPTH_TEST);
  634.     glEnable(GL_LIGHTING);
  635.     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
  636.     glCallList(list_lights_on);
  637.  
  638.     c = lights[n].diffuse;
  639.     glMaterialfv(GL_BACK, GL_AMBIENT, c.c);
  640.     glMaterialfv(GL_BACK, GL_DIFFUSE, black.c);
  641.     glMaterialfv(GL_BACK, GL_SPECULAR, black.c);
  642.  
  643.     glMaterialfv(GL_FRONT, GL_AMBIENT, (c * .75).c);
  644.     glMaterialfv(GL_FRONT, GL_DIFFUSE, white.c);
  645.     glMaterialfv(GL_FRONT, GL_SPECULAR, white.c);
  646.  
  647.     glMatrixMode(GL_MODELVIEW);
  648.     glPushMatrix();
  649.     glRotatef(-light_rotation[n], 0, 0, 1);
  650.     glTranslatef(lights[n].pos.pt[0], lights[n].pos.pt[1], 
  651.          lights[n].pos.pt[2]);
  652.     glRotatef(-degrees(atan2(lights[n].pos.pt[2] - sphere_position.pt[2],
  653.                  lights[n].pos.pt[0])), 0, 1, 0);
  654.     glCallList(list_light_draw);
  655.     glPopMatrix();
  656.  
  657.     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
  658.     glDisable(GL_LIGHTING);
  659.     glCallList(list_lights_off);
  660.     glDisable(GL_DEPTH_TEST);
  661.   } else {
  662.     /* 5.0.1 for Elans seems to object strongly to replacing
  663.      * empty display lists, so will put some stupid command
  664.      * in here */
  665.     glColor3f(0, 0, 0);
  666.   }
  667.   glEndList();
  668. }
  669.  
  670. static void light_draw_list_init()
  671. {
  672.   float c, s;
  673.   int t;
  674.  
  675.   glNewList(list_light_draw, GL_COMPILE);
  676.   glEnable(GL_NORMALIZE);
  677.   glMatrixMode(GL_MODELVIEW);
  678.   glPushMatrix();
  679.   glScalef(.25, .15, .15);
  680.   glBegin(GL_QUAD_STRIP);
  681.   for (t = 0; t <= spherediv; t++) {
  682.     c = cos(M_2PI * (float)t / (float)spherediv);
  683.     s = sin(M_2PI * (float)t / (float)spherediv);
  684.     glNormal3f(.25, .968*s, .968*c);
  685.     glVertex3f(0, s, c);
  686.     glVertex3f(1, .75*s, .75*c);
  687.   }
  688.   glEnd();
  689.   glNormal3f(1, 0, 0);
  690.   glBegin(GL_TRIANGLE_STRIP);
  691.   for (t = 0; t <= spherediv; t++) {
  692.     c = cos(M_2PI * (float)t / (float)spherediv);
  693.     s = sin(M_2PI * (float)t / (float)spherediv);
  694.     glVertex3f(1, .75*s, .75*c);
  695.     glVertex3f(1, 0, 0);
  696.   }
  697.   glEnd();
  698.   glPopMatrix();
  699.   glDisable(GL_NORMALIZE);
  700.   glEndList();
  701. }
  702.  
  703. static void lights_init()
  704. {
  705.   int i;
  706.  
  707.   for (i = 0; i < nlights; i++) {
  708.     glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lights[i].diffuse);
  709.     glLightfv(GL_LIGHT0 + i, GL_SPECULAR, black.c);
  710.     glLightfv(GL_LIGHT0 + i, GL_AMBIENT, black.c);
  711.     glLightf(GL_LIGHT0 + i, GL_SPOT_EXPONENT, 4);
  712.     glLightf(GL_LIGHT0 + i, GL_SPOT_CUTOFF, 90);
  713.   }
  714.  
  715.   glLightfv(GL_LIGHT0 + nlights, GL_DIFFUSE, black.c);
  716.   glLightfv(GL_LIGHT0 + nlights, GL_SPECULAR, black.c);
  717.   glLightfv(GL_LIGHT0 + nlights, GL_AMBIENT, world_ambient.c);
  718.   glEnable(GL_LIGHT0 + nlights);
  719.  
  720.   /* GL_LIGHT0 + nlights + 1 willl eventually be used to draw the 
  721.    * refractions - stay tuned. */
  722.   glLightfv(GL_LIGHT0 + nlights + 1, GL_DIFFUSE, black.c);
  723.   glLightfv(GL_LIGHT0 + nlights + 1, GL_SPECULAR, black.c);
  724.   glLightfv(GL_LIGHT0 + nlights + 1, GL_AMBIENT, white.c);
  725. }
  726.  
  727. static int lights_move(int light, float dr, float dphi, float dtheta,
  728.                int update)
  729. {
  730.   float cphi, sphi, x, y;
  731.   float r;
  732.   Point l, dl;
  733.  
  734.   if (!(dr || dphi || dtheta)) return 0;
  735.  
  736.   l = lights[light].pos - sphere_position;
  737.  
  738.   if (dr) {
  739.     dl = l + l*dr;
  740.     if (dl.mag() > sphere_size) l = dl;
  741.   }
  742.   
  743.   if (dphi) {
  744.     cphi = cos(dphi);
  745.     sphi = sin(dphi);
  746.     y = -l.pt[0]*sphi + l.pt[2]*cphi;
  747.     
  748.     /* This hack keeps with light from getting below the sphere - 
  749.      * the projection sections would completely freak if this ever
  750.      * happened  - sphere_size is multiplied by two as a fudge factor*/
  751.     if (y < 2.0*sphere_size) {
  752.       dphi = atan2(l.pt[2] - 2.0*sphere_size, l.pt[0]);
  753.       cphi = cos(dphi);
  754.       sphi = sin(dphi);
  755.       
  756.     }
  757.     x = l.pt[0];
  758.     l.pt[0] = x*cphi + l.pt[2]*sphi;
  759.     l.pt[2] = -x*sphi + l.pt[2]*cphi;
  760.   }
  761.  
  762.   if (dtheta) {
  763.     light_rotation[light] += degrees(dtheta);
  764.     light_rotation[light] = degrees_clamp(light_rotation[light]);
  765.   }
  766.  
  767.   lights[light].pos = l + sphere_position;
  768.   lights[light].pos.pt[3] = 1;
  769.  
  770.   lights_init_position(light);
  771.   lights_list_init(light);
  772.  
  773.   if (update) lights_move_update(light, dr ? 1 : 0, dphi ? 1 : 0, 
  774.                  dtheta ? 1 : 0);
  775.   return 1;
  776. }
  777.  
  778. static void lights_move_update(int light, int dr, int dphi, 
  779.                    int dtheta)
  780. {
  781.   if (dr) {
  782.     disk_build(light);
  783.     shadow_refraction_full_build(light);
  784.     shadow_list_init(light);
  785.     refraction_list_init(light);  
  786.   } else if (dphi) {
  787.     shadow_refraction_full_build(light);
  788.     shadow_list_init(light);
  789.     refraction_list_init(light);
  790.   } else if (dtheta) {
  791.   }
  792.  
  793. }
  794.  
  795.  
  796.  
  797.  
  798. static int get_lists(int size)
  799. {
  800.   int i;
  801.   i = glGenLists(size);
  802.   if (size && !i) {
  803.     fprintf(stderr, "Unable to allocate %d display lists.\n");
  804.     exit(1);
  805.   }
  806.   return i;
  807. }
  808.  
  809. static void lists_init()
  810. {
  811.   list_square = get_lists(1);
  812.   lists_shadows = get_lists(nlights);
  813.   lists_refraction = get_lists(nlights);
  814.   lists_lights = get_lists(nlights);
  815.   list_sphere = get_lists(1);
  816.   list_spheredisk = get_lists(1);
  817.   list_lights_on = get_lists(1);
  818.   list_lights_off = get_lists(1);
  819.   list_light_draw = get_lists(1);
  820.  
  821. //  sphere_build();
  822. }
  823.  
  824. static inline int sphere_npoints() 
  825. {
  826.   return (spherediv+1)*spherediv*3;
  827. }
  828.  
  829. void sphere_build()
  830. {
  831.   int nspherepts;
  832.   int r, t, index;
  833.   float c, s;
  834.       
  835.   delete spherepts;
  836.   nspherepts = sphere_npoints();
  837.   if (nspherepts == 0) return;
  838.   spherepts = new GLfloat[nspherepts];
  839.  
  840.   index = 0;
  841.   for (r = 0; r <= spherediv; r++) {
  842.     spherepts[index++] = sin(M_PI * (float)r / (float)spherediv);
  843.     spherepts[index++] = 0;
  844.     spherepts[index++] = -cos(M_PI * (float)r / (float)spherediv);
  845.   }
  846.   for (t = 1; t < spherediv; t++) {
  847.     c = cos(2.0 * M_PI * (float)t / (float)spherediv);
  848.     s = sin(2.0 * M_PI * (float)t / (float)spherediv);
  849.     for (r = 0; r <= spherediv; r++) {
  850.       spherepts[index++] = c*spherepts[r*3];
  851.       spherepts[index++] = s*spherepts[r*3];
  852.       spherepts[index++] = spherepts[r*3 + 2];
  853.     }
  854.   }
  855.  
  856. }
  857.  
  858. void sphere_list_init()
  859. {
  860.   glNewList(list_sphere, GL_COMPILE);
  861.   sphere_disk.draw_by_perimeter();
  862.   glEndList();
  863. }  
  864.  
  865. void sphere_draw()
  866. {
  867.   int r, t, p1, p2;
  868.  
  869.   for (t = 1; t < spherediv; t++) {
  870.     glBegin(GL_QUAD_STRIP);
  871.     p1 = (t - 1) * (spherediv + 1);
  872.     p2 = t * (spherediv + 1);
  873.     for (r = 0; r <= spherediv; r++, p1++, p2++) {
  874.       glNormal3fv(&spherepts[p1*3]);
  875.       glVertex3fv(&spherepts[p1*3]);
  876.       glNormal3fv(&spherepts[p2*3]);
  877.       glVertex3fv(&spherepts[p2*3]);
  878.     }
  879.     glEnd();
  880.   }
  881.  
  882.   glBegin(GL_QUAD_STRIP); 
  883.   p1 = (spherediv + 1) * (spherediv - 1);
  884.   p2 = 0;
  885.   for (r = 0; r <= spherediv; r++, p1++, p2++) {
  886.     glNormal3fv(&spherepts[p1*3]);
  887.     glVertex3fv(&spherepts[p1*3]);
  888.     glNormal3fv(&spherepts[p2*3]);
  889.     glVertex3fv(&spherepts[p2*3]);
  890.   }
  891.   glEnd();
  892. }
  893.  
  894. static void disk_build()
  895. {
  896.   int i;
  897.   for (i = 0; i < nlights; i++) disk_build(i);
  898. }
  899.  
  900. static void disk_build(int disk)
  901. {
  902.   Point light;
  903.   light = lights[disk].pos;
  904.  
  905.   disks[disk].free_points_normals();
  906.   disks[disk].free_colors();
  907.  
  908.   disks[disk].set_divisions(diskdiv, diskdiv);
  909.   disks[disk].set_angle(2.0 * 
  910.             acos(sphere_size / light.dist(sphere_position)));
  911.   disks[disk].fill_points();
  912. }
  913.  
  914. static void shadow_list_init()
  915. {
  916.   int i;
  917.   for (i = 0; i < nlights; i++) shadow_list_init(i);
  918. }
  919.  
  920. static void shadow_list_init(int n)
  921. {
  922.   Color c(square_ambient[0], square_ambient[1], square_ambient[2]);
  923.  
  924.   c *= world_ambient;
  925.  
  926.   glNewList(lists_shadows + n, GL_COMPILE);
  927.   glColorMask(lights[n].shadow_mask[0], lights[n].shadow_mask[1],
  928.           lights[n].shadow_mask[2], lights[n].shadow_mask[3]);
  929.   glDisable(GL_DEPTH_TEST);
  930.   glColor3fv(c.c);
  931.   shadows[n].draw_by_perimeter(0, 0, 1);
  932.   glColorMask(1, 1, 1, 1);
  933.   glEndList();
  934. }
  935.  
  936. static void refraction_list_init()
  937. {
  938.   int i;
  939.   for (i = 0; i < nlights; i++) refraction_list_init(i);
  940. }
  941.  
  942. static void refraction_list_init(int n) {
  943.   /* This could be loads simpler if it weren't for the texture mapping -
  944.    * that's where all this weirdness with GL_LIGHT0 + nlights + 1 comes 
  945.    * in */
  946.   glNewList(lists_refraction + n, GL_COMPILE);
  947.  
  948.   glEnable(GL_LIGHTING);
  949.   glCallList(list_lights_off);
  950.   /* This is white ambient light */
  951.   glEnable(GL_LIGHT0 + nlights + 1);
  952.   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, black.c);
  953.   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black.c);
  954.   glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
  955.   glEnable(GL_COLOR_MATERIAL);
  956.  
  957.   glBlendFunc(GL_ONE, GL_ONE);
  958.   glEnable(GL_BLEND);
  959.  
  960.   glDisable(GL_DEPTH_TEST);
  961.   refraction[n].draw();
  962.  
  963.   glDisable(GL_BLEND);
  964.  
  965.   glDisable(GL_COLOR_MATERIAL);
  966.   glDisable(GL_LIGHT0 + nlights + 1);
  967.   glDisable(GL_LIGHTING);
  968.  
  969.   glEndList();
  970. }
  971.  
  972. static void shadow_refraction_full_build()
  973. {
  974.   int i;
  975.   for (i = 0; i < nlights; i++) shadow_refraction_full_build(i);
  976. }
  977.  
  978. /* This entire function is written a bit oddly... */
  979. static void shadow_refraction_full_build(int n)
  980. {
  981.   Color c;
  982.   float dist_light;
  983.   Point dlight, zaxis;
  984.  
  985.   /* Make sure that we're starting over from scratch */
  986.   shadows[n].free_points_normals();
  987.   shadows[n].free_colors();
  988.   refraction[n].free_points_normals();
  989.   refraction[n].free_colors();
  990.  
  991.   dlight = lights[n].pos - sphere_position;
  992.   dist_light = dlight.mag();
  993.   dlight.unitize();
  994.   zaxis.pt[0] = 0;
  995.   zaxis.pt[1] = 0;
  996.   zaxis.pt[2] = 1;
  997.  
  998.   shadows[n].set_divisions(disks[n].get_rdivisions(), 
  999.                disks[n].get_tdivisions());
  1000.   refraction[n].set_divisions(disks[n].get_rdivisions(), 
  1001.                   disks[n].get_tdivisions());
  1002.  
  1003.   shadows[n].alloc_points();
  1004.   shadows[n].face_direction(dlight, disks[n]);
  1005.   shadows[n].scale_translate(sphere_size, sphere_position);
  1006.  
  1007.   c = square_diffuse;
  1008.   c *= lights[n].diffuse; 
  1009.  
  1010.   refraction[n].copy_points(disks[n]);
  1011.   refraction[n].set_colors(c);
  1012.   refraction[n].scale_colors_by_z();
  1013.  
  1014.   refraction[n].scale(sphere_size);
  1015.   refraction[n].refract_normals(zaxis * dist_light, index);
  1016.   refraction[n].face_direction(dlight);
  1017.  
  1018.   refraction[n].project_borrow_points(shadows[n]);  
  1019.   refraction[n].free_normals();
  1020.   shadows[n].project(lights[n].pos);
  1021.   if (index != 1.0) refraction[n].scale_colors_by_darea(shadows[n]);
  1022. }
  1023.  
  1024. int scene_load_texture(char *texfile)
  1025. {
  1026. #ifdef TEXTURE
  1027.   teximage = tkRGBImageLoad(texfile);
  1028. #else
  1029.   teximage = NULL;
  1030. #endif
  1031.  
  1032.   if (teximage == NULL) return 0;
  1033.   else return 1;
  1034. }
  1035.  
  1036. void texture_init()
  1037. {
  1038.   if (teximage == NULL) return;
  1039.  
  1040.   gluBuild2DMipmaps(GL_TEXTURE_2D, 3, teximage->sizeX, teximage->sizeY,
  1041.             GL_RGB, GL_UNSIGNED_BYTE, teximage->data);
  1042.  
  1043.   glMatrixMode(GL_TEXTURE);
  1044.   glLoadIdentity();
  1045.   glRotatef(90, 0, 0, 1);
  1046.   /* This scales the texture so that it fits on the square */
  1047.   glTranslatef(.5, .5, 0);
  1048.   glScalef(.1, .1, 1);
  1049.   glMatrixMode(GL_MODELVIEW);
  1050.  
  1051.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
  1052.          GL_NEAREST_MIPMAP_NEAREST);
  1053.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
  1054.          GL_LINEAR);
  1055. }
  1056.